home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / boot / netBoot.new / tftp.c < prev    next >
C/C++ Source or Header  |  1990-12-19  |  12KB  |  442 lines

  1. /*
  2.  * tftp.c
  3.  *
  4.  * @(#)tftp.c 1.9 88/02/08 Copyr 1986 Sun Micro
  5.  * Copyright (c) 1986 by Sun Microsystems, Inc.
  6.  *
  7.  * Standalone network boot via TFTP
  8.  */
  9. #ifdef sun4
  10. #define    SUN4
  11. #endif
  12. #ifdef sun3
  13. #define    SUN3
  14. #endif
  15. #include "machparam.h"
  16. #include "boot.h"
  17. #include "saio.h"
  18. #include "socket.h"
  19. #include "if.h"
  20. #include "in.h"
  21. #include "if_ether.h"
  22. #include "in_systm.h"
  23. #include "ip.h"
  24. #include "udp.h"
  25. #include "sainet.h"
  26. #include "sunromvec.h"
  27. #include "cpu.addrs.h"
  28. #include    <sys/exec.h>
  29.  
  30. #undef DEV_BSIZE
  31. #undef MAX
  32. #include "tftp.h"
  33.  
  34. #ifdef notdef
  35. #include "globram.h"
  36. #endif
  37.  
  38. #ifdef notdef
  39. #define millitime() (gp->g_nmiclock)
  40. #else
  41. #define millitime() (*romp->v_nmiclock)
  42. #endif
  43.                     /* tftp error messages */
  44. char    *tftp_errs[] = {
  45.     "not defined",
  46.     "file not found",
  47.     "access violation",
  48.     "disk full or allocation exceeded",
  49.     "illegal TFTP operation",
  50.     "unknown transfer ID",
  51.     "file already exists",
  52.     "no such user"
  53. };
  54.  
  55.                     /* TFTP packet */
  56. struct tftp_pack {
  57.     /* struct ether_header tf_ether; */    /* Ethernet header */
  58.     struct ip tf_ip;        /* IP header */
  59.     struct udphdr tf_udp;        /* UDP header */
  60.     struct tftphdr tf_tftp;        /* TFTP header */
  61.     char tftp_data[SEGSIZE];    /* TFTP data beyond header */
  62. };
  63. /*
  64.  * Size of Headers in TFTP DATA packet
  65.  */
  66. #define TFTPHDRLEN    (sizeof (struct ether_header) + sizeof (struct ip) + \
  67.              sizeof (struct udphdr) + 4)
  68.  
  69. struct tftpglob {
  70.     struct tftp_pack tf_out;    /* outgoing TFTP packet */
  71.     struct sainet tf_inet;        /* Internet state */
  72.     struct ether_header in_etherheader; 
  73.     char    tf_tmpbuf[1600];    /* tmp for incoming packets */
  74.     int    tf_block;        /* current block number */
  75.     char    *tf_data;        /* current load pointer */
  76. };
  77.  
  78. #if defined(SUN4) && defined(CACHE)            /* for loading into cache */
  79. #define LOADADDR 0x20000
  80. #define TFTPBASE ((struct tftpglob *) 0xFFDC0300)
  81. #else CACHE
  82. #define LOADADDR 0x4000
  83. #define TFTPBASE    ((struct tftpglob *)0x3000)
  84. #endif SUN4 && CACHE
  85.  
  86. #define    REXMIT_MSEC    4000        /* 4 seconds between retransmits */
  87.  
  88. /*
  89.  * Description: Entry point for initializing the ethernet during boot.
  90.  *
  91.  * Synopsis:    status = etheropen(sip)
  92.  *        status    :(int) 0 command complete
  93.  *        sip    :(char *) pointer to saioreq structure
  94.  *
  95.  * Routines:    bzero, inet_init
  96.  */
  97. etheropen(sip)
  98.     register struct saioreq *sip;
  99. {
  100.     register struct tftpglob *tf = TFTPBASE;
  101.  
  102.     bzero((caddr_t)tf, sizeof(*tf));    /* clear tftp work space */
  103.  
  104.     inet_init(sip, &tf->tf_inet, tf->tf_tmpbuf); /* get internet address */
  105.     return (0);
  106. }
  107.  
  108. #ifdef SUN2
  109. etherstrategy(sip, rw)
  110.     register struct saioreq *sip;
  111.     int rw;
  112. {
  113.     printf("tftp: random access attempted - code error.\n");
  114.     return(-1);
  115. }
  116. #endif SUN2
  117.  
  118. /*
  119.  * Description: Loads the boot routine across the ethernet
  120.  *
  121.  * Synopsis:    status = tftpload(sip)
  122.  *        status    :(int)    load address
  123.  *                  -1 error
  124.  *        sip    :(char *) pointer to saioreq structure
  125.  *
  126.  * Routines:    bzero
  127.  *
  128.  * Variables:    locked    :(int) lock in host and server
  129.  *        firsttry:(int) first try flag for autoboot
  130.  */
  131. tftpload(sip, bp)
  132.     register struct saioreq *sip;
  133.         struct bootparam   *bp ;
  134. {
  135.     register struct tftpglob    *tf = TFTPBASE;
  136.     register struct tftp_pack   *out = &tf->tf_out;
  137.     register struct tftp_pack   *in = (struct tftp_pack *)tf->tf_tmpbuf;
  138.     register char            *p, *q, *x;
  139.     register short            i, len;
  140.     int                autoboot = 0;
  141.     int                firsttry = 0;
  142.     int                feedback = 0;
  143.     int finished = 0;
  144.     int                delay = REXMIT_MSEC;
  145.     int                time, xcount, locked, retry;
  146.     char                *ind = "-=-=";
  147. #ifdef SUN4
  148.         u_long                temp=0;
  149. #endif SUN4
  150.     struct exec *header;
  151.                         /* if unit # is 0, this is
  152.                          * an autoboot */
  153.     if (sip->si_unit == 0)
  154.                 autoboot = 1;
  155. top:
  156.                         /* Initialize IP header */
  157.     out->tf_ip.ip_v = IPVERSION;        /* IP version number */
  158.     out->tf_ip.ip_hl = sizeof(struct ip) / 4;/* header length */
  159.     out->tf_ip.ip_ttl = MAXTTL;        /* time to live */
  160.     out->tf_ip.ip_p = IPPROTO_UDP;        /* type of protocol */
  161.  
  162.                         /* set source address */
  163.  
  164.     bcopy(&tf->tf_inet.sain_myaddr, &out->tf_ip.ip_src, sizeof(out->tf_ip.ip_src));
  165.      
  166.                         /* set destination address,
  167.                          * Dst host is argument with
  168.                          * our net number plugged in */
  169.     if (autoboot && firsttry == 0) {
  170.                         /* send to host from revarp */
  171.  
  172. #ifdef SUN4
  173.             out->tf_ip.ip_dst.S_un.S_un_b.s_b1=
  174.                   tf->tf_inet.sain_hisaddr.S_un.S_un_b.s_b1;
  175.             out->tf_ip.ip_dst.S_un.S_un_b.s_b2=
  176.                   tf->tf_inet.sain_hisaddr.S_un.S_un_b.s_b2;
  177.             out->tf_ip.ip_dst.S_un.S_un_b.s_b3=
  178.                   tf->tf_inet.sain_hisaddr.S_un.S_un_b.s_b3;
  179.             out->tf_ip.ip_dst.S_un.S_un_b.s_b4=
  180.                   tf->tf_inet.sain_hisaddr.S_un.S_un_b.s_b4;
  181. #else SUN4
  182.         out->tf_ip.ip_dst.s_addr = tf->tf_inet.sain_hisaddr.s_addr;
  183. #endif SUN4
  184.         firsttry = 1;
  185.     } else if (autoboot && firsttry > 0) {
  186.                         /* broadcast? */
  187. #ifdef SUN4
  188.         out->tf_ip.ip_dst.S_un.S_un_b.s_b1=(-1);
  189.         out->tf_ip.ip_dst.S_un.S_un_b.s_b2=(-1);
  190.         out->tf_ip.ip_dst.S_un.S_un_b.s_b3=(-1);
  191.         out->tf_ip.ip_dst.S_un.S_un_b.s_b4=(-1);
  192. #else SUN4
  193.         out->tf_ip.ip_dst.s_addr = -1;
  194. #endif SUN4
  195.     } else {
  196.                         /* unit specified */
  197.  
  198. #ifdef SUN4
  199.         struct in_addr  in;
  200.         bcopy(&out->tf_ip.ip_src.s_addr, &in, sizeof(in));
  201.         temp = in.s_addr;
  202.         temp -= in_lnaof(in);
  203.         temp += sip->si_unit;
  204.         bcopy(&temp, &out->tf_ip.ip_dst.s_addr, sizeof(temp));
  205. #else SUN4
  206.         out->tf_ip.ip_dst.s_addr = out->tf_ip.ip_src.s_addr +
  207.                 sip->si_unit  - in_lnaof(out->tf_ip.ip_src);
  208. #endif SUN4
  209.     }
  210.  
  211.                         /* initialize UDP header */
  212.  
  213.     out->tf_udp.uh_sport =  (millitime() & 1023) + 1024;/* source post */
  214.     out->tf_udp.uh_dport =  IPPORT_TFTP;    /* destination port */
  215.     out->tf_udp.uh_sum =  0;        /* no checksum */
  216.  
  217.                         /* set tftpglob structure */
  218.     tf->tf_block = 1;
  219.     tf->tf_data = (char *)KERNEL_START;
  220.                         /* Create the TFTP Read Request
  221.                          * packet */
  222.     out->tf_tftp.th_opcode = RRQ;
  223.                         /* load internet address */
  224.     q = bp->bp_name;
  225.     p = out->tf_tftp.th_stuff;
  226.     while (*q && *q != ' ') {
  227.         *(p++) = *(q++);
  228.     }
  229.     *p++ = 0;
  230.         q = "octet";
  231.         while (*p++ = *q++)
  232.                 ;
  233.                                                 /* fill UDP packet */
  234.     out->tf_udp.uh_ulen = sizeof (struct udphdr) + 2 + 
  235.             (p - out->tf_tftp.th_stuff);
  236.                         /* fill ip packet */
  237.  
  238.     out->tf_ip.ip_len = sizeof (struct ip) + out->tf_udp.uh_ulen;
  239.  
  240.                         /* init. transmit status */
  241.     locked = 0;
  242.     retry = 0;
  243.     time = millitime();
  244.                         /* transmit loop */
  245.     for (xcount = 0; xcount < 5;) {        /* try to xmit 5 times */
  246.         if (millitime() >= time) {
  247.             time = millitime() + delay;
  248.  
  249.                         /* limit delay to 64 sec */
  250.             delay = delay < 64000 ? delay * 2 : 64000;
  251.  
  252.                         /* show activity */
  253.             printf("%c\b", ind[feedback++ % 4]);
  254.  
  255.                         /* transmit */
  256.  
  257.             if (ip_output(sip, 
  258.                 ((caddr_t)out) - sizeof (struct ether_header) ,
  259.                 out->tf_ip.ip_len + sizeof (struct ether_header), 
  260.                 &tf->tf_inet, tf->tf_tmpbuf))
  261.                 printf("X\b");
  262.                         /* 5 times if not locked */
  263.             if (locked == 0 || retry > 15)
  264.                 xcount++;
  265.             else 
  266.                 retry++;
  267.         }
  268.                         /* get input IP packet */
  269.  
  270.         len = ip_input(sip,((caddr_t)in) - sizeof(struct ether_header),
  271.             &tf->tf_inet);
  272.  
  273.                         /* check length of packet */
  274.         if (len < TFTPHDRLEN) {
  275. #ifdef debugjl
  276. /*printf(" not tftp packet\n");*/
  277. #endif debugjl
  278.             continue;
  279.         }
  280.                         /* check packet type */
  281.  
  282.         if (in->tf_ip.ip_p != IPPROTO_UDP ||
  283.             in->tf_udp.uh_dport != out->tf_udp.uh_sport)  {
  284. #ifdef debugjl
  285. printf(" wrong packet type = %x\n",in->tf_ip.ip_p);
  286. #endif debugjl
  287.             continue;
  288.             }
  289.                         /* dst has been locked in */
  290. #ifdef SUN4
  291.         if ( locked &&
  292.                     ( (out->tf_ip.ip_dst.S_un.S_un_b.s_b1 != 
  293.                       in->tf_ip.ip_src.S_un.S_un_b.s_b1) ||      
  294.                      (out->tf_ip.ip_dst.S_un.S_un_b.s_b2 != 
  295.                       in->tf_ip.ip_src.S_un.S_un_b.s_b2) ||      
  296.                      (out->tf_ip.ip_dst.S_un.S_un_b.s_b3 != 
  297.                       in->tf_ip.ip_src.S_un.S_un_b.s_b3) ||      
  298.                      (out->tf_ip.ip_dst.S_un.S_un_b.s_b4 != 
  299.                       in->tf_ip.ip_src.S_un.S_un_b.s_b4)) )
  300. #else SUN4
  301.         if (locked &&
  302.                     out->tf_ip.ip_dst.s_addr != in->tf_ip.ip_src.s_addr)
  303. #endif SUN4
  304. #ifdef debugjl
  305.             { 
  306.             printf(" not locked address = %x%x%x%x\n",
  307.             out->tf_ip.ip_dst.S_un.S_un_b.s_b1,
  308.             out->tf_ip.ip_dst.S_un.S_un_b.s_b2,
  309.             out->tf_ip.ip_dst.S_un.S_un_b.s_b3,
  310.             out->tf_ip.ip_dst.S_un.S_un_b.s_b4);
  311.             continue;
  312.             }
  313. #else
  314.             continue;
  315. #endif debugjl
  316.                         /* error */
  317.  
  318.         if (in->tf_tftp.th_opcode == ERROR) {
  319.             if (autoboot && tf->tf_block == 1)
  320.                 continue;
  321.             if (in->tf_tftp.th_code < 0 ||
  322.                 in->tf_tftp.th_code > sizeof(tftp_errs)/sizeof(char *)){
  323.                 printf("tftp: Unknown error 0x%x\n",
  324.                     in->tf_tftp.th_code);
  325.             } else {
  326.                 printf("tftp: %s @ block %d\n",
  327.                     tftp_errs[in->tf_tftp.th_code], tf->tf_block);
  328.             }
  329.                         /* for autoboot, keep looping */
  330.             if (autoboot)
  331.                 goto top;
  332.             return (-1);
  333.         }
  334.                         /* we are looking for data */
  335.  
  336.         if (in->tf_tftp.th_opcode != DATA ||
  337.             in->tf_tftp.th_block  != tf->tf_block) 
  338. #ifdef debugjl
  339.             { 
  340.             printf(" not data packet");
  341.             continue;
  342.             }
  343. #else
  344.             continue;
  345. #endif debugjl
  346.                         /* in sequence DATA packet */
  347.         if (tf->tf_block == 1) {    
  348.                         /* lock onto server port */
  349.  
  350.             out->tf_udp.uh_dport = in->tf_udp.uh_sport;
  351.  
  352.                         /* for autoboot, get address */
  353.             if (autoboot) 
  354.                 bcopy(&(in->tf_ip.ip_src),&(out->tf_ip.ip_dst),
  355.                     sizeof(in->tf_ip.ip_src));
  356.  
  357.                         /* print server found */
  358.  
  359.             printf("Booting from tftp server at "); 
  360.                         inet_print(out->tf_ip.ip_dst);
  361.             locked = 1;
  362.         }
  363.                         /* calc. data length */
  364.  
  365.         len = in->tf_udp.uh_ulen - (sizeof(struct udphdr) + 4);
  366.  
  367.                         /* copy data to load point */
  368.         if (len) {
  369.             bcopy(in->tf_tftp.th_data, tf->tf_data, len);
  370.             if (tf->tf_block == 1) {
  371.                 header = (struct exec *)tf->tf_data;
  372.                 printf("Size: %d", header->a_text);
  373.             }
  374.             tf->tf_data += len;
  375.             if (header->a_text) {
  376.                 header->a_text -= len;
  377.                 if (tf->tf_block == 1) {
  378.                 /*
  379.                  * If on first block, don't count header size against the
  380.                  * text size.
  381.                  */
  382.                 header->a_text += sizeof(struct exec);
  383.                 }
  384.                 if ((int)header->a_text <= 0) {
  385.                 printf("+%d", header->a_data);
  386.                 header->a_data += header->a_text;
  387.                 header->a_text = 0;
  388.                 }
  389.             } else {
  390.                 header->a_data -= len;
  391.                 if ((int)header->a_data <= 0) {
  392.                 printf("+%d\n", header->a_bss);
  393.                 finished = 1;
  394.                 }
  395.             }
  396.         }
  397.                         /* send ACK (acknowledge) */
  398.         out->tf_tftp.th_opcode = ACK;
  399.         out->tf_tftp.th_block = tf->tf_block++;
  400.         out->tf_udp.uh_ulen = sizeof (struct udphdr) + 4;
  401.         out->tf_ip.ip_len = sizeof (struct ip) + out->tf_udp.uh_ulen;
  402.  
  403.                             /* transmit */
  404.  
  405.         if (ip_output(sip, (caddr_t)out - sizeof(struct ether_header),
  406.             out->tf_ip.ip_len +
  407.             sizeof (struct ether_header), &tf->tf_inet,
  408.             tf->tf_tmpbuf))
  409.             printf("X\b");
  410.                         /* reset count and retry */
  411.         xcount = 0;
  412.         retry = 0;
  413.         printf("%c\b", ind[feedback++ % 4]);    /* Show activity */
  414.  
  415.                         /* reset delay */
  416.         delay = REXMIT_MSEC;
  417.         time = millitime()+delay;
  418.                         /* check if end of file */
  419.         if ((len < SEGSIZE)  || finished) {
  420. #ifndef sun4
  421.             /*
  422.              * Zero out the uninitialized data, since Sprite
  423.              * doesn't do it for
  424.              * itself...
  425.              */
  426.             tf->tf_data += (int)header->a_data;
  427.             bzero(tf->tf_data, header->a_bss);
  428. #endif        
  429.             printf("Downloaded %d bytes from tftp server.\n\n",
  430.                 tf->tf_data - KERNEL_START);
  431.             return (KERNEL_START + sizeof(struct exec));
  432.         }
  433.     }
  434.     printf("tftp: time-out.\n");
  435.                         /* for autoboot, loop forever */
  436.     if (autoboot)
  437.         goto top;
  438.                         /* error return */
  439.     return (-1);
  440. }
  441.  
  442.